package com.yupi.yupicturebackend.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.yupicturebackend.mapper.NFTAssetMapper;
import com.yupi.yupicturebackend.model.dto.blockchain.*;
import com.yupi.yupicturebackend.model.entity.NFTAsset;
import com.yupi.yupicturebackend.service.NFTAssetService;
import com.yupi.yupicturebackend.utils.BlockchainNFTUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * NFT资产服务实现
 *
 * @author yupi
 */
@Slf4j
@Service
public class NFTAssetServiceImpl extends ServiceImpl<NFTAssetMapper, NFTAsset> implements NFTAssetService {

    @Resource
    private NFTAssetMapper nftAssetMapper;

    @Override
    public NFTMintResult mintNFT(String imageUrl, NFTConfig nftConfig, Long userId) {
        try {
            log.info("开始铸造NFT: imageUrl={}, userId={}", imageUrl, userId);
            
            // 生成NFT唯一标识
            String nftId = IdUtil.fastSimpleUUID();
            
            // 创建NFT记录
            NFTAsset nftAsset = new NFTAsset();
            nftAsset.setNftId(nftId);
            nftAsset.setUserId(userId);
            nftAsset.setName(nftConfig.getName());
            nftAsset.setDescription(nftConfig.getDescription());
            nftAsset.setCreator(nftConfig.getCreator());
            nftAsset.setCreatorAddress(nftConfig.getCreatorAddress());
            nftAsset.setCurrentOwner(nftConfig.getCreator());
            nftAsset.setOwnerAddress(nftConfig.getCreatorAddress());
            nftAsset.setImageUrl(imageUrl);
            nftAsset.setNetwork(nftConfig.getNetwork());
            nftAsset.setRoyaltyBps(nftConfig.getRoyaltyBps());
            nftAsset.setRoyaltyRecipient(nftConfig.getRoyaltyRecipient());
            nftAsset.setTradeable(nftConfig.getTradeable());
            nftAsset.setTransferable(nftConfig.getTransferable());
            nftAsset.setRarity(nftConfig.getRarity());
            nftAsset.setCollection(nftConfig.getCollection());
            nftAsset.setTags(JSONUtil.toJsonStr(nftConfig.getTags()));
            nftAsset.setAttributes(JSONUtil.toJsonStr(nftConfig.getAttributes()));
            nftAsset.setStatus("minting");
            nftAsset.setViewCount(0L);
            nftAsset.setLikeCount(0L);
            nftAsset.setCreateTime(new Date());
            nftAsset.setUpdateTime(new Date());
            
            // 保存到数据库
            this.save(nftAsset);
            
            // 调用区块链铸造
            NFTMintResult mintResult = BlockchainNFTUtils.mintNFT(imageUrl, nftConfig);
            
            // 更新铸造结果
            if (mintResult.getSuccess()) {
                nftAsset.setTokenId(mintResult.getTokenId());
                nftAsset.setContractAddress(mintResult.getContractAddress());
                nftAsset.setTransactionHash(mintResult.getTransactionHash());
                nftAsset.setImageHash(mintResult.getImageHash());
                nftAsset.setMetadataHash(mintResult.getMetadataHash());
                nftAsset.setMintCost(mintResult.getMintCost());
                nftAsset.setGasFee(mintResult.getGasFee());
                nftAsset.setConfirmations(mintResult.getConfirmations());
                nftAsset.setMarketplaceUrl(mintResult.getMarketplaceUrl());
                nftAsset.setStatus("active");
            } else {
                nftAsset.setStatus("failed");
            }
            
            nftAsset.setUpdateTime(new Date());
            this.updateById(nftAsset);
            
            log.info("NFT铸造完成: nftId={}, success={}", nftId, mintResult.getSuccess());
            return mintResult;
            
        } catch (Exception e) {
            log.error("NFT铸造失败: imageUrl={}", imageUrl, e);
            throw new RuntimeException("NFT铸造失败", e);
        }
    }

    @Override
    public boolean updateMintStatus(String nftId, NFTMintResult mintResult) {
        NFTAsset nftAsset = this.getOne(new QueryWrapper<NFTAsset>().eq("nftId", nftId));
        if (nftAsset == null) {
            return false;
        }
        
        if (mintResult.getSuccess()) {
            nftAsset.setTokenId(mintResult.getTokenId());
            nftAsset.setContractAddress(mintResult.getContractAddress());
            nftAsset.setTransactionHash(mintResult.getTransactionHash());
            nftAsset.setStatus("active");
        } else {
            nftAsset.setStatus("failed");
        }
        
        nftAsset.setUpdateTime(new Date());
        return this.updateById(nftAsset);
    }

    @Override
    public NFTTradeResult tradeNFT(NFTTradeConfig tradeConfig, Long userId) {
        try {
            log.info("开始NFT交易: tokenId={}, userId={}", tradeConfig.getTokenId(), userId);
            
            // 验证NFT所有权
            NFTAsset nftAsset = this.getOne(new QueryWrapper<NFTAsset>()
                    .eq("tokenId", tradeConfig.getTokenId())
                    .eq("userId", userId));
            
            if (nftAsset == null || !nftAsset.getTradeable()) {
                throw new RuntimeException("NFT不存在或不可交易");
            }
            
            // 执行区块链交易
            NFTTradeResult tradeResult = BlockchainNFTUtils.tradeNFT(tradeConfig);
            
            // 更新NFT信息
            if (tradeResult.getSuccess()) {
                nftAsset.setCurrentOwner(tradeConfig.getToAddress());
                nftAsset.setOwnerAddress(tradeConfig.getToAddress());
                nftAsset.setLastTradePrice(tradeConfig.getPrice());
                nftAsset.setLastTradeTime(new Date());
                nftAsset.setUpdateTime(new Date());
                this.updateById(nftAsset);
            }
            
            log.info("NFT交易完成: tokenId={}, success={}", tradeConfig.getTokenId(), tradeResult.getSuccess());
            return tradeResult;
            
        } catch (Exception e) {
            log.error("NFT交易失败: tokenId={}", tradeConfig.getTokenId(), e);
            throw new RuntimeException("NFT交易失败", e);
        }
    }

    @Override
    public List<NFTAsset> getUserNFTs(Long userId, Integer limit) {
        return nftAssetMapper.selectByUserId(userId, limit != null ? limit : 20);
    }

    @Override
    public NFTAsset getNFTByContractAndTokenId(String contractAddress, String tokenId) {
        return nftAssetMapper.selectByContractAndTokenId(contractAddress, tokenId);
    }

    @Override
    public List<NFTAsset> searchNFTs(String keyword, Integer limit) {
        return nftAssetMapper.searchNFTs(keyword, limit != null ? limit : 20);
    }

    @Override
    public List<NFTAsset> getNFTsByPriceRange(BigDecimal minPrice, BigDecimal maxPrice, String currency, Integer limit) {
        return nftAssetMapper.selectByPriceRange(minPrice, maxPrice, currency, limit != null ? limit : 20);
    }

    @Override
    public List<NFTAsset> getPopularNFTs(Integer limit) {
        return nftAssetMapper.selectPopularNFTs(limit != null ? limit : 20);
    }

    @Override
    public List<NFTAsset> getLatestMintedNFTs(Integer limit) {
        return nftAssetMapper.selectLatestMinted(limit != null ? limit : 20);
    }

    @Override
    public List<NFTAsset> getNFTsByCreator(String creator, Integer limit) {
        return nftAssetMapper.selectByCreator(creator, limit != null ? limit : 20);
    }

    @Override
    public List<NFTAsset> getNFTsByCollection(String collection, Integer limit) {
        return nftAssetMapper.selectByCollection(collection, limit != null ? limit : 20);
    }

    @Override
    public List<NFTAsset> getNFTsByRarity(String rarity, Integer limit) {
        return nftAssetMapper.selectByRarity(rarity, limit != null ? limit : 20);
    }

    @Override
    public boolean incrementViewCount(Long nftId) {
        return nftAssetMapper.incrementViewCount(nftId) > 0;
    }

    @Override
    public boolean likeNFT(Long nftId, Long userId) {
        // 这里可以添加防重复点赞的逻辑
        return nftAssetMapper.incrementLikeCount(nftId) > 0;
    }

    @Override
    public boolean updateNFTPrice(Long nftId, BigDecimal price, String currency, Long userId) {
        // 验证所有权
        if (!verifyNFTOwnership(nftId, userId)) {
            return false;
        }
        
        return nftAssetMapper.updatePrice(nftId, price, currency) > 0;
    }

    @Override
    public boolean transferNFT(Long nftId, String newOwner, String newOwnerAddress, Long userId) {
        // 验证所有权
        if (!verifyNFTOwnership(nftId, userId)) {
            return false;
        }
        
        return nftAssetMapper.updateOwner(nftId, newOwner, newOwnerAddress) > 0;
    }

    @Override
    public Map<String, Object> getNFTStatistics(Long userId) {
        Map<String, Object> statistics = new HashMap<>();
        
        if (userId != null) {
            // 用户NFT统计
            Long userNFTCount = nftAssetMapper.countByUserId(userId);
            statistics.put("userNFTCount", userNFTCount);
            
            // 用户NFT总价值
            List<NFTAsset> userNFTs = this.getUserNFTs(userId, null);
            BigDecimal totalValue = userNFTs.stream()
                    .filter(nft -> nft.getCurrentPrice() != null)
                    .map(NFTAsset::getCurrentPrice)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            statistics.put("totalValue", totalValue);
        }
        
        // 全局统计
        List<Map<String, Object>> networkStats = nftAssetMapper.countByNetwork();
        statistics.put("networkStats", networkStats);
        
        List<Map<String, Object>> statusStats = nftAssetMapper.countByStatus();
        statistics.put("statusStats", statusStats);
        
        return statistics;
    }

    @Override
    public boolean verifyNFTOwnership(Long nftId, Long userId) {
        NFTAsset nftAsset = this.getById(nftId);
        return nftAsset != null && Objects.equals(nftAsset.getUserId(), userId);
    }

    @Override
    public List<NFTMintResult> batchMintNFTs(List<String> imageUrls, NFTConfig nftConfig, Long userId) {
        List<NFTMintResult> results = new ArrayList<>();
        
        for (String imageUrl : imageUrls) {
            try {
                NFTMintResult result = this.mintNFT(imageUrl, nftConfig, userId);
                results.add(result);
            } catch (Exception e) {
                log.error("批量铸造NFT失败: imageUrl={}", imageUrl, e);
                NFTMintResult errorResult = new NFTMintResult();
                errorResult.setSuccess(false);
                errorResult.setErrorMessage(e.getMessage());
                results.add(errorResult);
            }
        }
        
        return results;
    }

    @Override
    public List<Map<String, Object>> getNFTTradeHistory(Long nftId) {
        // 这里应该查询NFT交易历史表
        // 暂时返回空列表
        return new ArrayList<>();
    }

    @Override
    public boolean setNFTTradeable(Long nftId, Boolean tradeable, Long userId) {
        // 验证所有权
        if (!verifyNFTOwnership(nftId, userId)) {
            return false;
        }
        
        NFTAsset nftAsset = this.getById(nftId);
        nftAsset.setTradeable(tradeable);
        nftAsset.setUpdateTime(new Date());
        
        return this.updateById(nftAsset);
    }

    @Override
    public List<NFTAsset> getRecommendedNFTs(Long userId, Integer limit) {
        // 基于用户历史行为推荐NFT
        // 这里简化为返回热门NFT
        return this.getPopularNFTs(limit);
    }
}
